// import com->alibaba->druid->string_ptr ;
// import com->alibaba->druid->sql->SQLUtils;
// import com->alibaba->druid->sql->ast->*;
// import com->alibaba->druid->sql->ast->expr->*;
// import com->alibaba->druid->sql->dialect->odps->ast->OdpsUDTFSQLSelectItem;
// import com->alibaba->druid->sql->visitor->SQLASTVisitor;
// import com->alibaba->druid->sql->visitor->SQLASTVisitorAdapter;
// import com->alibaba->druid->util->FnvHash;

// import java->util->ArrayList;
// import java->util->Collections;
// import java->util->std::list;
// import java->util->TreeSet;
#pragma once

#include <string>
#include <list>

#include "../SQLExpr.h"
#include "../SQLExprImpl.h"
#include "../Object.h"
#include "../SQLName.h"
#include "../SQLObjectImpl.h"
#include "../SQLReplaceable.h"
#include "../SQLDbTypedObject.h"
#include "../SQLOrderBy.h"
#include "../SQLWindow.h"

// #include "../../visitor/SQLASTVisitor.h"
// #include "../../visitor/SQLASTVisitorAdapter.h"

#include "SQLSelectQueryBase.h"
#include "SQLSelect.h"
#include "SQLExprTableSource.h"
#include "SQLSelectGroupByClause.h"
#include "SQLTableSource.h"

#include "../../../DbType.h"

class SQLSelect;

class SQLSelectQueryBlock : virtual public SQLSelectQueryBase, virtual public SQLReplaceable, virtual public SQLDbTypedObject
{
public:
  static string_ptr class_;
  int distionOption;
  SQLSelectItem_list_ptr selectList;

  SQLTableSource_ptr from;
  SQLExprTableSource_ptr into;
  SQLExpr_ptr where;

  // for oracle & oceanbase
  SQLExpr_ptr startWith;
  SQLExpr_ptr connectBy;
  BOOL_ptr prior;
  BOOL_ptr noCycle;
  SQLOrderBy_ptr orderBySiblings;

  SQLSelectGroupByClause_ptr groupBy;
  std::shared_ptr<std::list<SQLWindow_ptr>> windows;
  SQLExpr_ptr qualify;
  SQLOrderBy_ptr orderBy;
  BOOL_ptr forUpdate;
  BOOL_ptr noWait;
  BOOL_ptr skipLocked;
  BOOL_ptr forShare;
  SQLExpr_ptr waitTime;
  SQLLimit_ptr limit_;

  // for oracle
  SQLExpr_list_ptr forUpdateOf;
  SQLSelectOrderByItem_list_ptr distributeBy;
  SQLSelectOrderByItem_list_ptr sortBy;
  SQLSelectOrderByItem_list_ptr clusterBy;

  string_ptr cachedSelectList; // optimized for SelectListCache
  long cachedSelectListHash;   // optimized for SelectListCache

  DbType_ptr dbType;
  SQLCommentHint_list_ptr hints;

  SQLSelectQueryBlock();

  SQLSelectQueryBlock(DbType_ptr dbType);
  SHAREDOBJECT(SQLSelectQueryBlock);

  SQLExprTableSource_ptr getInto();

  void setInto(SQLExpr_ptr into);

  void setInto(SQLExprTableSource_ptr into);

  SQLSelectGroupByClause_ptr getGroupBy();

  void setGroupBy(SQLSelectGroupByClause_ptr x);

  std::shared_ptr<std::list<SQLWindow_ptr>> getWindows();

  void addWindow(SQLWindow_ptr x);

  SQLExpr_ptr getQualify();

  void setQualify(SQLExpr_ptr x);

  SQLExpr_ptr getWhere();

  void setWhere(SQLExpr_ptr x);

  void addWhere(SQLExpr_ptr condition);

  void addWhereForDynamicFilter(SQLExpr_ptr condition);

  void whereOr(SQLExpr_ptr condition);

  void addHaving(SQLExpr_ptr condition);

  SQLOrderBy_ptr getOrderBy();

  void setOrderBy(SQLOrderBy_ptr orderBy);

  void addOrderBy(SQLOrderBy_ptr orderBy);

  void addOrderBy(SQLSelectOrderByItem_ptr orderByItem);

  BOOL_ptr containsOrderBy(SQLSelectOrderByItem_ptr orderByItem);

  void addOrderBy(SQLExpr_ptr orderBy, SQLOrderingSpecification_ptr type);

  void addOrderBy(SQLExpr_ptr orderBy);

  SQLOrderBy_ptr getOrderBySiblings();

  void setOrderBySiblings(SQLOrderBy_ptr orderBySiblings);

  int getDistionOption();

  void setDistionOption(int distionOption);

  void setDistinct();

  BOOL_ptr isDistinct();

  SQLSelectItem_list_ptr getSelectList();

  SQLSelectItem_ptr getSelectItem(int i);

  void addSelectItem(SQLSelectItem_ptr item);

  SQLSelectItem_ptr addSelectItem(SQLExpr_ptr expr);

  void addSelectItem(string_ptr selectItemExpr, string_ptr alias);

  void addSelectItem(SQLExpr_ptr expr, string_ptr alias);

  // static class AggregationStatVisitor extends SQLASTVisitorAdapter ;
  class AggregationStatVisitor /* : virtual public  SQLASTVisitorAdapter */
  {
  public:
    BOOL_ptr aggregation;

    // BOOL_ptr visit(SQLAggregateExpr* x) {
    //     aggregation = BOOL::TRUE;
    //     return BOOL::FALSE;
    // }
  };

  BOOL_ptr hasSelectAggregation();

  SQLTableSource_ptr getFrom();

  void setFrom(SQLExpr_ptr from);

  void setFrom(SQLTableSource_ptr from);

  void setFrom(SQLSelectQueryBlock_ptr queryBlock, string_ptr alias);

  void setFrom(SQLSelect_ptr select, string_ptr alias);

  void setFrom(string_ptr tableName, string_ptr alias);

  BOOL_ptr isForUpdate();

  void setForUpdate(BOOL_ptr forUpdate);

  BOOL_ptr isNoWait();

  void setNoWait(BOOL_ptr noWait);

  BOOL_ptr isSkipLocked();

  void setSkipLocked(BOOL_ptr skipLocked);

  BOOL_ptr isForShare();

  void setForShare(BOOL_ptr forShare);

  SQLExpr_ptr getWaitTime();

  void setWaitTime(SQLExpr_ptr waitTime);

  SQLLimit_ptr getLimit();

  void setLimit(SQLLimit_ptr limit);

  void mergeLimit(SQLLimit_ptr limit);

  SQLExpr_ptr getFirst();

  void setFirst(SQLExpr_ptr first);

  SQLExpr_ptr getOffset();

  void setOffset(SQLExpr_ptr offset);

  BOOL_ptr isPrior();

  void setPrior(BOOL_ptr prior);

  SQLExpr_ptr getStartWith();

  void setStartWith(SQLExpr_ptr startWith);

  SQLExpr_ptr getConnectBy();

  void setConnectBy(SQLExpr_ptr connectBy);

  BOOL_ptr isNoCycle();

  void setNoCycle(BOOL_ptr noCycle);

  SQLSelectOrderByItem_list_ptr getDistributeBy();
  SQLSelectOrderByItem_list_ptr getDistributeByDirect();

  void addDistributeBy(SQLExpr_ptr x);

  void addDistributeBy(SQLSelectOrderByItem_ptr item);

  SQLSelectOrderByItem_list_ptr getSortBy();
  SQLSelectOrderByItem_list_ptr getSortByDirect();

  void addSortBy(SQLSelectOrderByItem_ptr item);

  void accept0(SQLASTVisitor_ptr visitor);

  bool equals(Object_ptr o);

  int hashCode();

  BOOL_ptr equalsForMergeJoin(SQLSelectQueryBlock *that);

  // SQLSelectQueryBlock* clone() ;
  virtual SQLObject_ptr clone();

  SQLExpr_list_ptr getForUpdateOf();

  int getForUpdateOfSize();

  void cloneSelectListTo(SQLSelectQueryBlock *x);

  void cloneTo(SQLSelectQueryBlock_ptr x);

  SQLTableSource_ptr findTableSource(string_ptr alias);
  SQLTableSource_ptr findTableSourceWithColumn(string_ptr column);
  SQLTableSource_ptr findTableSourceWithColumn(long columnHash);

  BOOL_ptr replace(SQLExpr_ptr expr, SQLExpr_ptr target);

  SQLSelectItem_ptr findSelectItem(string_ptr ident);

  SQLSelectItem_ptr findSelectItem(long identHash);

  BOOL_ptr selectItemHasAllColumn();

  BOOL_ptr selectItemHasAllColumn(BOOL_ptr recursive);

  SQLSelectItem_ptr findAllColumnSelectItem();

  // SQLColumnDefinition* findColumn(string_ptr  columnName) ;

  // SQLColumnDefinition* findColumn(long columnNameHash) ;

  SQLObject_ptr resolveColum(long columnNameHash);

  void addCondition(string_ptr conditionSql);

  void addCondition(SQLExpr_ptr expr);

  BOOL_ptr removeCondition(string_ptr conditionSql);

  BOOL_ptr removeCondition(SQLExpr_ptr condition);

  void limit(int rowCount, int offset);

  string_ptr getCachedSelectList();

  void setCachedSelectList(string_ptr cachedSelectList, long cachedSelectListHash);

  long getCachedSelectListHash();

  DbType_ptr getDbType();

  void setDbType(DbType_ptr dbType);

  SQLCommentHint_list_ptr getHintsDirect();

  SQLCommentHint_list_ptr getHints();

  void setHints(SQLCommentHint_list_ptr hints);

  int getHintsSize();

  BOOL_ptr replaceInParent(SQLSelectQuery *x);

  SQLSelectOrderByItem_list_ptr getClusterBy();
  SQLSelectOrderByItem_list_ptr getClusterByDirect();

  void addClusterBy(SQLSelectOrderByItem_ptr item);

  string_list_ptr computeSelecteListAlias();

  SQLTableSource_list_ptr  getMappJoinTableSources();

  BOOL_ptr clearMapJoinHint();

  bool containsAttribute(string_ptr name){};
  void addBeforeComment(string_list_ptr comments){};
  void addBeforeComment(wstring_list_ptr comments){};
  string_list_ptr getAfterCommentsDirect(){};
  string_list_ptr getBeforeCommentsDirect(){};
  void addAfterComment(string_ptr comment){};
  void addAfterComment(string_list_ptr comments){};
  bool hasBeforeComment(){};
  bool hasAfterComment(){};
};
